Cluster Autoscaler
개요
재밌게도, 여러 툴들을 한 레포에서 autoscaler라는 묶음으로 관리하고 있다.
각각이 하는 역할이 다르기에 나는 이를 구분해서 문서로 작성하고자 한다.
클러스터의 노드가 부족할 때 자동으로 늘리는 툴.
파드를 늘리는 HPA, Vertical Pod Autoscaler과는 다르게 노드를 늘려서 추가 자원을 확보한다.
이를 통해 인프라를 프로비저닝하는 환경에 대한 각종 커스텀이 필요하다.
요즘에는 Karpenter를 사용할 수 없는 환경에서만 쓰이는 것 같다.
원리
기본적으로 클러스터 오토스케일러는 현재 클러스터의 상태를 감시한다.
- 10초마다 파드의 상태를 감시한다.
- pending 상태인 파드가 있으면 외부 제공자에게 관리를 해야 함을 통지한다.
- aws의 경우라면 autoscaling group에 api를 날린다.
- 이후 외부 제공자가 노드를 추가하거나, 삭제해준다.
그러면 이후에 노드를 추가하거나 삭제를 해주는 것은 전적으로 외부 제공자의 책임이 된다.
가령 AWS에서는 오토스케일링그룹을 통해 노드가 추가, 삭제된다.
기능
클러스터 스케일 업
자원 부족으로 인해 파드가 스케줄에 실패했을 때 클러스터 오토스케일러가 동작한다.
즉, 스케줄링이 실패했을 때만 발동한다는 것이다.
이것은 cpu의 사용량을 기반으로 스케일링을 하는 다른 노드 스케일러 솔루션과 차별되는 점이다.
구체적으로는 다음의 과정을 따른다.
--scan-interval
(기본 10초)마다 kube-apiserver를 통해schedulable: False
상태이면서 이유가unschedulable
인 파드의 상태를 관찰한다.- 그러한 파드를 찾으면 노드를 증설하기 위한 시도를 한다.
- 노드들은 노드 그룹으로 묶인 것으로 간주하며, 같은 스펙의 노드를 증설한다.
이 스케일러는 노드를 만들고 노드 오브젝트를 등록하는 작업에 책임을 지지 않는다.
그저 --max-node-provision-time
(기본 15분)내에 클라우드 제공자가 적절하게 노드를 붙여주기를 바랄 뿐이다.
이 시간 내에 노드가 등록되지 않으면 노드가 등록되지 않았다고 간주하고 새로 노드를 증설해달라 찡찡댄다.
클러스터 스케일 다운
자원이 지나치게 남아돌면서 중요도가 적은 파드들이 위치한 노드가 있을 때도 노드를 줄이는 방향으로 동작한다.
이때 어떤 파드가 있는 노드들이 살아남을 수 있을까?
- PDB로 빡센 제한이 걸린 파드
kube-system
네임스페이스에서 데몬셋이 아닌 채 노드에 배치된 파드- 디플로이먼트과 같은 관리자가 따로 없는 스탠드 얼론 파드
- 로컬스토리지 종속성이 있는 파드
- 스케줄링 조건에 걸려 다른 곳으로 가기 힘든 파드
"cluster-autoscaler.kubernetes.io/safe-to-evict": "false"
어노테이션이 걸린 파드
이런 파드들이 위치한 노드라면 해당 노드는 지워지지 않을 것이다.
emptyDir은 파드 내에서만 쓰이는 건데 이걸 로컬 종속성이 있다는 이유로 제외하는 게 맞나?
어차피 휘발될 거 감안하고 쓰는 스토리지인데..
아예 특정 노드를 사라지지 않게 하고 싶다면 노드에 "cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"
어노테이션을 걸어준다.
스케일 다운은 아래의 과정을 따른다.
--scan-interval
마다 쓸모없는 노드를 탐색한다.- 노드 내의
request / allocatable
, 즉 사용량이--scale-down-utilization-threshold
(기본 50퍼) 밑인 노드 - 그러면서 살아남을 수 있는 파드가 없는 노드
- 그러면서 스케일 다운 불가 어노테이션이 붙지 않는 노드
- 노드 내의
- 이 노드가 10분 동안 쓸모 없음 상태라면 종료시킨다.
- 그런 노드가 많더라도, 10분마다 하나씩 노드를 종료시키며 스케일 다운이 가능한지는 매번 다시 계산한다.
오버프로비저닝
리소스가 많이 필요할 것이 예상되는 시점에 미리 스케일 업을 해두고 싶다면 이런 식의 꼼수를 부릴 수 있다.
일단 임의의 파드를 늘린다.
다만 이 파드의 우선순위를 극한으로 낮춰서 다른 필요한 파드가 배치돼야할 때 언제든지 축출될 수 있도록 한다.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: overprovisioning
value: -10
globalDefault: false
description: "Priority class used by overprovisioning."
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: overprovisioning
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: overprovisioning
template:
metadata:
labels:
run: overprovisioning
spec:
priorityClassName: overprovisioning
terminationGracePeriodSeconds: 0
containers:
- name: reserve-resources
image: registry.k8s.io/pause:3.9
resources:
requests:
cpu: "200m"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: overprovisioning-autoscaler
namespace: default
labels:
app: overprovisioning-autoscaler
spec:
selector:
matchLabels:
app: overprovisioning-autoscaler
replicas: 1
template:
metadata:
labels:
app: overprovisioning-autoscaler
spec:
containers:
- image: registry.k8s.io/cluster-proportional-autoscaler-amd64:1.8.1
name: autoscaler
command:
- /cluster-proportional-autoscaler
- --namespace=default
- --configmap=overprovisioning-autoscaler
- --default-params={"linear":{"coresPerReplica":1}}
- --target=deployment/overprovisioning
- --logtostderr=true
- --v=2
serviceAccountName: cluster-proportional-autoscaler-service-account
단점
이 친구는 실상 Karpenter를 쓸 수 없는 환경에서 사용하는 차안 같은 느낌이다.
왜냐하면 아래의 문제점들이 있기 때문이다.
- 직접적으로 노드 생성에 관여하지 않는다.
- 클러스터에서 노드는 제거됐으나, 실제 인스턴스는 살아있다던가 하는 간극이 발생할 수 있다.
- 같은 영역에 노드가 생겨야 하는데 엉뚱한 AZ에 노드가 추가되어 같이 써야 할 자원을 못 쓰는 경우도 생긴다.
- 확장, 축소 정책이 다양하지 않다.
- 노드를 빠르게 줄이기도 어렵고, 스케일 업 시에도 비용 최적화를 고려하기 힘들다.
- 느리다.
- 직접 노드 생성에 관여하지 않으니 홉이 늘어나고, 이 홉에는 자체적으로 스케일링을 관리하는 리소스가 추가적으로 있다보니 실제 클러스터가 확장되는데에는 오랜 시간이 걸린다.
관련 문서
이름 | noteType | created |
---|---|---|
Cluster Autoscaler | knowledge | 2025-03-05 |